he parameter you use,  the safer your shutdown will be.  If you have to resort to 0 (re-boot), you will have the long wait for boot up associated with turning the computer off then on.

Memory Functions:
Block Move
Moves blocks of memory.  Requires three parameters: source address, destination address, and length.  Enter these three address after one another on the line and hit return.
Block Compare
Compares blocks of memory using the same three parameters as the Block Move command.  Any differences will be displayed as "Mismatch at xxxx/yyyy" where xxxx is the address of the source and yyyy is the address of the destination where the blocks do not match.
Fill
Fills a block of memory with a specified value.  Takes four parametes with the fourth being optional: beginning address, ending address, fill value, and optionally, the size of the fill value - 1 for byte fill, 2 for word fill, and 4 for long word fill.
Find
Finds a specified value in a specified range of memory.  Takes four parameters: search value, search value size (same as size from Fill command above), start address and end address.  If any matches are found, they will be displayed between the curly braces.
Template
Displays a memory location as if it were a Mac data structure, showing you all the current values.  TMON currently knows only four data structures: WindowRecord, ControlRecord, TERecord, and ParamBlock (see IM for descriptions of these).  Clicking on the Template line hitting Return will cycle through these four templates.  Template takes one parameter, an address.  So, after finding the structure you wish to display, enter an address that contains a structure of that type and hit return.  TMON will list all current values for the fields of that structure.  Note that information will be meaningless unless there is actually a structure of the desired type at the address you specify.  This command could be helpful in looking at key disk checkers by allowing you to look at the ParamBlock the program is currently using to read the disk - although I have never used this.
Stack addresses
Attempts to recognize as labels the supplied address.  This function defaults to an address of SP - stack pointer.  To use this, just click to left of SP and hit return.  The function will then look at the first address on the stack and see if it matches any labels that it currently knows.  For example, right after a JSR, the stack contains the return address.  If TMON k knows a label for the return address (and it will if there was a label to the left of the JSR in the assembly window) then using the Stack Addresses command will display the label in curly braces.  Hitting return repeatedly will then move up the stack, analysing each successive stack address.  Click in front of the SP and hit return to reset the command to the original stack pointer.
Stack crawl
Attempts to find the return address of a procedure that has a currently active stack frame.  Remember that most compiled programs use the LINK and UNLK instructions to set up stack frames to temprarily store local variables.  If you know what register is being used as the stack frame pointer (A6 is the only one I have ever seen and this is the default value TMON uses), then the Stack Crawl can use that register to analyse the stack and try to determine the return address and display it in the curly braces.
Load resource
Loades the resource specified by the two parameters (type and id #) into memory and displays the address of the resource in the curly braces.
Print
Allows you to print listings longer that contained in the active window.  Clicking on the Print line and hitting return toggles the print mode between Dump, Assembly, File, and Heap.  Once the mode has been selected, the print command needs a start and end address.  Type these in, hit return, and TMON will print the desired output to the serial port (meaning that you cannot use a laserwriter, but you can use an imagewriter.)

A000 Trap Functions:
Trap record
Unknown.  Allows you to record any traps called by the program, but requires a lot of complicated set up.
Record
Unknown.  Used to allocate a table for trap record (above).
Trap
Unknown.  Used by programmers to test the heap anytime a trap that affects the heap zone is called.  We don't need this to crack.
Heap
Unknown.  Similar to Trap but doesn't wait for a trap to execute.  We don't need this one either.
Trap discipline
A programmer's feature.  Trap discipline is a means of checking traps for faulty parameters.  Select a range of traps and a PC range (see Trap Intercept below) and TMON will check all traps within that range.  If it finds a trap with questionable parameters, the monitor will be entered.  There are two strengths of discipline: lenient and strict.  To toggle these, click on the trap discipline line and hit return.
Trap checksum
Unknown.  Another function that programmers would use to check application problems.  Since we are cracking an application that already works, we don't need this one.
Checksum
Unknown.  Used to specify the checksum for Trap Checksum.
Trap intercept
Allows you to specify a trap or range of traps that, when encountered, will cause the monitor to be entered.  Simply click on the line and enter the trap name WITH a leading underscore, a space, and then the second trap.  This specifies a range of traps to look for, the range being in numerical order of trap numbers.  If only one trap is specified, only that trap will be checked.  Use this to catch a program that uses a dialog to prompt for a serial number.  If the trap entered is _ModalDialog, the monitor will be entered just before the dialog is drawn.  Optionally, a PC range may be entered after the trap range.  This would specify that TMON regain control only if the specified trap is encountered within the specified PC range.  I have never used a PC range.
Trap signal
Similar to Trap Interrupt, except that once the trap range and optional PC range have been entered, the user must hit the interrupt switch to enter the monitor.  Once the interrupt switch (or Programmer's Key) has been pressed, TMON will continue execution until a trap within the specified range has been encountered.
Options / Cmd-o
Allows setting of seven monitor global functions.  I am not exactly clear what the various settings mean, so I jus leave them all on.
Print / Cmd-p
Causes the active window to be dumped to whatever port has been set during setup (achieved by launching the TMON application).  This prints a window's contents only!  To get long printouts, use the print command in the User Window.

How to crack Sorcerer
We are now going to look at a typical key-disk protection scheme.  The important concepts to grasp here are how to quickly isolate the protection, and then how to remove it.  Don't worry too much about the particulars, unless you happen to have a copy of Sorcerer you want to crack.
First off, how do we know that it is protected?  Dumb question, but this is really important to beginning the crack.  With Sorcerer, we note that when launched from the hard drive, it brings up a dialog box (or alert) requesting the key disk.  So the logical place to start is with Resedit to try and figure out what resource the program is using to display the alert.
After you open the application in Resedit, we see the following:

Well, there are no ALRT or DLOG resources, so the program is generating its own dialog internally.  If there was a set of ALRT or DLOG resources, we would quickly scan them and try to determine which was the one that the program displays to request the key-disk.  If we could locate the ID # of the correct DLOG resource, we would go into Nosy and bring up the Traps ref map, see which procs called GetNewDialog, or Alert (if the resource in question was ALRT), and then check all the procs Nosy listed to see which one called GetNewDialog with the ID # we had found in Resedit.
Often you will find that there are DLOGs or ALRTs, but none of them have the correct message.  If this is the case, then we would be in the same spot we are right now.  The next thing to consider is that the string "Please Insert the Original Disk" (or whatever the string is) has to come from somewhere.  You can try to locate it in Nosy, but often the string will be in a string resource.  Look at the Resedit window above, and note the STR resource.  Let's take a look:
 
Perfect!  There is the culprit.  So, all we have to do is find the part of Sorcerer that uses STR resource # 256.  Since there are several ways to load a string, you might want to forget the Traps ref map and start tracing the program.  If the program is huge, this might not be the way to go.  If you look at the Traps ref map for Sorcerer, you would eventually find that proc108 calls the trap GetString.  This would be an excellent place to start.  Otherwise you might just find the proc called Sorcerer and start tracing there...An important note:  tracing programs from start to error sucks.  If you can figure out which trap is causing the problem, then by all means do so.  If you are not familiar enough with the various traps, then you might well have to trace.  Get a hold of IM and learn the Dialog Manager and the Resource Manager!
OK, let's start with the procedure Sorcerer:

   D50:                                 QUAL    Sorcerer ; b# =59  s#1  =proc38

   D50: 4EBA 004C      1000D9E Sorcerer JSR     proc39
   D54: 4E56 0000      'NV..'           LINK    A6,#0
   D58: 2C5F           ',_'             POP.L   A6
   D5A: 4E55 FCB6      'NU..'           LINK    A5,#-$34A
   D5E: 9FED 0010          $10          SUBA.L  glob27(A5),A7
   D62: 4EBA 0042      1000DA6          JSR     proc41
   D66: 41ED FCB2        -$34E          LEA     glob2(A5),A0
   D6A: 2F08           '/.'             PUSH.L  A0
   D6C: 4EBA F292      1000000          JSR     proc1
   D70: A8FE           '..'             _InitFonts  
   D72: 3F3C FFFF      '?<..'           PUSH    #$FFFF
   D76: 4267           'Bg'             CLR     -(A7)
   D78: 4EBA F49A      1000214          JSR     FlushEvents
   D7C: A912           '..'             _InitWindows  
   D7E: A9CC           '..'             _TeInit  
   D80: 42A7           'B.'             CLR.L   -(A7)
   D82: A97B           '.'             _InitDialogs ; (resumeProc:ProcPtr) 
   D84: A850           '.P'             _InitCursor  
   D86: 4EAD 0092      20003F6          JSR     proc108(A5)
   D8A: 4EBA 0390      100111C          JSR     proc54
   D8E: 4EBA 0156      1000EE6          JSR     %_TERM
   D92: 4E5D           'N]'             UNLK    A5
   D94: 4EBA 000E      1000DA4          JSR     proc40
   D98: 4E75           'Nu'             RTS     

   D9A: 4E5E                   data20   DC.B    'N^Nu'

A quick scan should reveal that possible problem areas are proc39, proc41, proc1, proc108, and proc54 since these are procedures that we can't see from this listing which is normal enough by itself.  Luckily, if you were to look at the first three procs called, they are very short and very benign.  If these were long, complex procedures, I might seriously consider going into TMON and setting a Trap Intercept to pick up _InitFonts so that TMON would grab control of the program early.  Then when I launch Sorcerer, if TMON breaks in then the error is later in the program, but if Sorcerer bombs, then the error was before the InitFonts.  That is a quick way to locate the problem.
So, let's take a look at the next procedure, proc108:

   3F6:                                 QUAL    proc108 ; b# =194  s#2  =proc108

                               vem_1     VEQU  -1040
                               vem_2     VEQU  -1038
                               vem_3     VEQU  -1036
                               vem_4     VEQU  -1034
                               vem_5     VEQU  -1030
                               vem_6     VEQU  -774
                               vem_7     VEQU  -512
   3F6:                                 VEND    

                               ;-refs -  1/proc37     1/Sorcerer  

   3F6: 4A6F EBE6      'Jo..'  proc108  TST     -$141A(A7)
   3FA: 4E56 FBE6      'NV..'           LINK    A6,#-$41A
   3FE: 48E7 0F18      'H...'           MOVEM.L D4-D7/A3-A4,-(A7)
   402: 41EE FE00      200FE00          LEA     vem_7(A6),A0
   406: 2848           '(H'             MOVEA.L A0,A4
   408: 486E FBFA      200FBFA          PEA     vem_5(A6)
   40C: 486E FBF0      200FBF0          PEA     vem_1(A6)
   410: 486E FBF6      200FBF6          PEA     vem_4(A6)
   414: A9F5           '..'             _GetAppParms ; (VAR apName:Str255; VAR apRefNum:INTEGER; VAR apParam:Handle) 
   416: 4267           'Bg'             CLR     -(A7)
   418: 41EE FCFA      200FCFA          LEA     vem_6(A6),A0
   41C: 2F08           '/.'             PUSH.L  A0
   41E: 486E FBF2      200FBF2          PEA     vem_2(A6)
   422: 4EAD 0052      1000162          JSR     GetVol(A5)
   426: 3E1F           '>.'             POP     D7
   428: 4267           'Bg'             CLR     -(A7)
   42A: 486E FBFA      200FBFA          PEA     vem_5(A6)
   42E: 3F2E FBF2      200FBF2          PUSH    vem_2(A6)
   432: 3F3C 0010      '?<..'           PUSH    #16
   436: 2F0C           '/.'             PUSH.L  A4
   438: 4267           'Bg'             CLR     -(A7)
   43A: 4EBA FDBE      20001FA          JSR     proc103
   43E: 181F           '..'             POP.B   D4
   440: 4267           'Bg'             CLR     -(A7)
   442: 3F2E FBF2      200FBF2          PUSH    vem_2(A6)
   446: 2F0C           '/.'             PUSH.L  A4
   448: 4EBA FED8      2000322          JSR     proc105
   44C: 101F           '..'             POP.B   D0
   44E: 0A00 0001      '....'           EORI.B  #1,D0
   452: 6700 00A0      20004F4          BEQ     lem_2
   456: 4267           'Bg'             CLR     -(A7)
   458: 3F3C 0002      '?<..'           PUSH    #2
   45C: 3F2E FBF2      200FBF2          PUSH    vem_2(A6)
   460: 2F0C           '/.'             PUSH.L  A4
   462: 4EBA FF0C      2000370          JSR     proc106
   466: 101F           '..'             POP.B   D0
   468: 0A00 0001      '....'           EORI.B  #1,D0
   46C: 6700 0086      20004F4          BEQ     lem_2
   470: 4267           'Bg'             CLR     -(A7)
   472: 3F3C 0001      '?<..'           PUSH    #1
   476: 3F2E FBF2      200FBF2          PUSH    vem_2(A6)
   47A: 2F0C           '/.'             PUSH.L  A4
   47C: 4EBA FEF2      2000370          JSR     proc106
   480: 101F           '..'             POP.B   D0
   482: 0A00 0001      '....'           EORI.B  #1,D0
   486: 676C           20004F4          BEQ.S   lem_2
   488: 42A7           'B.'             CLR.L   -(A7)
   48A: 3F3C 0101      '?<..'           PUSH    #257
   48E: 42A7           'B.'             CLR.L   -(A7)
   490: 70FF           'p.'             MOVEQ   #-1,D0
   492: 2F00           '/.'             PUSH.L  D0
   494: A9BD           '..'             _GetNewWindow ; (windowID:INTEGER; wStorage:Ptr; behind:WindowPtr):WindowPtr 
   496: 265F           '&_'             POP.L   A3
   498: 2F0B           '/.'             PUSH.L  A3
   49A: A873           '.s'             _SetPort ; (port:GrafPtr) 
   49C: 3F3C 0010      '?<..'           PUSH    #16
   4A0: 3F3C 001C      '?<..'           PUSH    #28
   4A4: A893           '..'             _MoveTo ; (h,v:INTEGER) 
   4A6: 4267           'Bg'             CLR     -(A7)
   4A8: A887           '..'             _TextFont ; (font:FontCode) 
   4AA: 42A7           'B.'             CLR.L   -(A7)
   4AC: 3F3C 0100      '?<..'           PUSH    #256
   4B0: A9BA           '..'             _GetString ; (stringID:INTEGER):StringHandle 
   4B2: 2C1F           ',.'             POP.L   D6
   4B4: 2046           ' F'             MOVEA.L D6,A0
   4B6: 2F10           '/.'             PUSH.L  (A0)
   4B8: A884           '..'             _DrawString ; (s:Str255) 
   4BA: 4267           'Bg'             CLR     -(A7)
   4BC: 42A7           'B.'             CLR.L   -(A7)
   4BE: 3F3C 0001      '?<..'           PUSH    #1
   4C2: 4EAD 002A      1000186          JSR     Eject(A5)
   4C6: 3E1F           '>.'             POP     D7
   4C8: 486E FBF4      200FBF4 lem_1    PEA     vem_3(A6)
   4CC: 4EBA FEEE      20003BC          JSR     proc107
   4D0: 4267           'Bg'             CLR     -(A7)
   4D2: 3F2E FBF4      200FBF4          PUSH    vem_3(A6)
   4D6: 2F0C           '/.'             PUSH.L  A4
   4D8: 4EBA FE48      2000322          JSR     proc105
   4DC: 1A1F           '..'             POP.B   D5
   4DE: 4267           'Bg'             CLR     -(A7)
   4E0: 42A7           'B.'             CLR.L   -(A7)
   4E2: 3F2E FBF4      200FBF4          PUSH    vem_3(A6)
   4E6: 4EAD 002A      1000186          JSR     Eject(A5)
   4EA: 3E1F           '>.'             POP     D7
   4EC: 1005           '..'             MOVE.B  D5,D0
   4EE: 67D8           20004C8          BEQ     lem_1
   4F0: 2F0B           '/.'             PUSH.L  A3
   4F2: A914           '..'             _DisposWindow ; (theWindow:WindowPtr) 
   4F4: 4CDF 18F0      'L...'  lem_2    MOVEM.L (A7)+,D4-D7/A3-A4
   4F8: 4E5E           'N^'             UNLK    A6
   4FA: 4E75           'Nu'             RTS     

   4FC: '............'         data76   DC.W    $8100,8,0,$4FC,$FC00,0
The first thing to do here is to quickly scan for trap names.  There are quite a few, but one should stick out.  Remember that we are looking for some reference to STR #256.  Note the GetString trap.  Immediately before the trap is a PUSH #256...that's our guy!  So, at this point, we know where the string is being loaded and drawn.  Since this procedure is called from the Main procedure, we can bet that the key-disk check is also in this proc.  Note that this is not always the case - often when you find the procedure that loads the dialog or string, you need to back trace to find out where the actual error generator is located.  That is where the Refs line (right below the VEND) in the listing comes in handy.  Note that this proc is called by not only Sorcerer, but also by proc37.  This might mean that the program checks the key-disk later in its execution.  But if you load up proc37, you would find that it simply Unloads the segment so it is harmless.
At this point, all we need to do is disable the disk-check.  So, start scanning down the listing and ask yourself "Where is a branch that will skip over the GetString trap?".  If you find that branch and make it always branch then odds are the program is cracked.  Nosy will help out here.  We are looking for a spot in the listing that a branch can jump to that will skip over the error.  We have two choices in this listing: lem_1 and lem_2.  Check out lem_1, and you will see a couple of problems with it.  First of all, see what piece of code branches to it.  There is a JSR  Eject, then a test, and a BEQ lem_1.  Also note that there is a DisposeWindow after it.  We might guess that DisposeWindow is disposing the error dialog.  We might also guess that lem_1 is being used as a loop to eject bad disks and request key-disks.  Well, let's give lem_2 a shot.  Now this one looks good - it is located right down at the procedures exit, so, if something is branching here, all the above stuff gets skipped.
So, just select lem_2 and hit cmd-f to let Nosy find all the references to lem_2 in the listing.  Line 452 is the key.  Note, D0 gets a result from an unknow procedure, then is EORd with 1, and then the branch occurs.  It sure looks like changing that branch from BEQ to BRA would gurrantee that the error never occured.  Let's try it.  From the assembly instruction listing, we see that BEQ is 67, and BRA is 60.  So, look at the first line in the above listing and we see that it is segment 2.  So, open CODE resource 2 in Resedit, and skip down to address 456 (remember, take the Nosy address and add 4 to find the Resedit address).  

There it is, on line 450.  See the 6700?  That sure matches what we find in Nosy, so that is our guy.  Change the 67 to 60 by clicking to the right of the 67, hitting backspace or delete, and typing 60.  That's it!  Now quit Resedit and save changes.  Launch the program and the protection is gone!
Let me quickly mention one last thing.  The above crack involved looking for a branch that would skip over the problem area, and making damn sure that that branch always executed.  But suppose that the program was setup so that after the disk check, the program branched to the error section.  In this case, we would want to make sure the branch never executed.  There are two ways to do this.  First off, you can change the branch to its logical opposite - BCC to BCS, BNE to BEQ, etc.  That way, the condition that triggers the error will now trigger the opposite, and run properly.  The second method is to simply replace the trap with a NOP.  That way, the branch never executes no matter what happens.
Look for upcoming material on more specific cracking methods and more actual cracks.
later

- The Shepherd